#ifndef __INCCJ
#define __INCCJ
	#include "collapsej.h"
	#include <ctype.h>

	


QClass * InitializeQClass(char * name){
	QClass *qc = (QClass*)malloc(sizeof(QClass));
	qc->name = (char*)malloc( sizeof(char)* strlen(name) +1 );
	strcpy(qc->name,name);
	qc->code_length=0;
	qc->access_modifier.line=-1;
	strcpy(qc->access_modifier.name,"");
	return qc;
}

QState * InitializeQState(char * name){
	QState *qs = (QState*)malloc(sizeof(QState));
	qs->name = (char*)malloc( sizeof(char)* strlen(name) +1 );
	strcpy(qs->name,name);
	qs->code_length=0;
	qs->access_modifier.line=-1;
	qs->qbehaviors = InitializeLinkedList();
	strcpy(qs->access_modifier.name,"");
	return qs;
}

QBehavior * InitializeQBehavior(char * name){
	QBehavior *qb = (QBehavior*)malloc(sizeof(QBehavior));
	qb->name = (char*)malloc( sizeof(char)* strlen(name) +1 );
	strcpy(qb->name,name);
	qb->code_length=0;
	qb->access_modifier.line=-1;
	strcpy(qb->access_modifier.name,"");
	return qb;
}


char * createStates(LinkedList * qclasses,FILE * output){
	int i,j;
	Node ** classes_array;
	Node ** states_array;
	
	if (qclasses == NULL || qclasses->length == 0){
		printf("No quantum states were found.\n");
		return NULL;
	}
	classes_array = getArray(qclasses);
	
	
	for(i=0;i<qclasses->length;++i){
		QClass * qc = classes_array[i]->value;
		#ifdef DEBUG
		printf("Working inside qclass [%s]\n",qc->name);
		#endif
		if (qc->qstates == NULL || qc->qstates->length == 0){
			printf("\tNo quantum states were found.\n");
			return NULL;
		}
		states_array = getArray(qc->qstates);
		
		//so as we have at least one quantum state, we need to declare the abstract class responsible
		//to hold the Data Structure behavior
		fprintf(output,"abstract class %sDataStructureImpl {\n",qc->name);
		fprintf(output,"\tprotected %sBehaviorStrategy qbs;\n",qc->name);
		//start
		for(j=0;j<qc->qstates->length;++j){
			QState * qs = states_array[j]->value;
			int count = 0;
			#ifdef DEBUG
			printf("\tWorking inside qstate [%s]\n",qs->name);
			#endif
			for(count=0;count < qs->code_length;count++)
				fprintf(output,"%c",qs->code[count]);
				}
		//end
		fprintf(output,"\tabstract void qBehavior();\n}\n");
		
		if(qc->qbehaviors->length > 0){
			//ok, we have at least one quantum behavior, so lets apply the Strategy Pattern :-)
			fprintf(output, "interface %sBehaviorStrategyImpl {\n",qc->name);
			fprintf(output, "\tabstract void qBehavior(%sDataStructureImpl dsi);\n}\n",qc->name);
		}
		for(j=0;j<qc->qstates->length;++j){
			QState * qs = states_array[j]->value;
			#ifdef DEBUG
			printf("\tWorking inside qstate [%s]\n",qs->name);
			#endif
			char * string;
			int count = 0;
			printf("HERE1 - ACCESS MODIFIER.LINE = [%d]\n",qs->access_modifier.line);
			if(qs->access_modifier.line > 0)
				fprintf(output,"%s ",qs->access_modifier.name);
			fprintf(output,"class %s extends %sDataStructureImpl{\n",qs->name,qc->name);
			//for(count=0;count < qs->code_length;count++)
				//fprintf(output,"%c",qs->code[count]);
			
			//break the line after the code
			fprintf(output,"\n");
			
			
			if (qs->qbehaviors->length > 1)
				fprintf(output,"TODO: implement condition for more than one quantum behavior");
			else if (qs->qbehaviors->length == 1){
				QBehavior * qb = getQBehavior(((QBehavior *)(qs->qbehaviors->tail->value))->name,qc);
				int temp=0;
				if (qb==NULL){
					printf("\tQBehavior [%s] was not found!\n",((QBehavior *)(qs->qbehaviors->tail->value))->name);
					return NULL;
				}
				
				
				if(qb->access_modifier.line > 0)
					fprintf(output,"%s ",qb->access_modifier.name);
				//TODO: check if a quantum behavior will always be void.
				
				fprintf(output,"void qBehavior() {\n\tqbs = new %sBehaviorStrategy(%sBehaviors.%s);\n\tqbs.qBehavior(this);\n\t}\n",qc->name,qc->name,toUpperCase(qb->name));
			}
			fprintf(output,"}\n");
		}
		
		//create one class to hold the ground state
		fprintf(output,"class %s%s extends %sDataStructureImpl{\n",qc->name,"GroundState",qc->name);
		fprintf(output,"void qBehavior() {\t //dummy behavior for Ground State \n}\n");
		fprintf(output,"}\n");
		
		
		//now lets print the enum-based abstract factory
		fprintf(output,"enum %sDSTypes{\n",qc->name);
		for(j=0;j<qc->qstates->length;++j){
			QState * qs = states_array[j]->value;
			//if(j > 0)
				//fprintf(output,",\n");
			fprintf(output,"\t%s {\n\t\t%sDataStructureImpl factoryMethod(){\n\t\t\treturn new %s();\n\t\t}\n\t},\n",toUpperCase(qs->name),qc->name,qs->name); 
		}
		//add the ground state!
		fprintf(output,"\t%s {\n\t\t%sDataStructureImpl factoryMethod(){\n\t\t\treturn new %s%s();\n\t\t}\n\t};","GROUNDSTATE",qc->name,qc->name,"GroundState"); 
		
		fprintf(output,"\n\tabstract %sDataStructureImpl factoryMethod();\n}\n",qc->name);
		
		fprintf(output,"\nclass %sDataStructure {\n",qc->name);
		fprintf(output,"\tprivate %sDataStructureImpl dsi;\n",qc->name);
		fprintf(output,"\tpublic %sDataStructure(%sDSTypes d){\n",qc->name,qc->name);
		fprintf(output,"\t\tdsi = d.factoryMethod();\n\t}\n");
		fprintf(output,"\tpublic %sDataStructureImpl getDSImp(){\n\t\treturn this.dsi;\n\t}\n}\n",qc->name);




	}


}

char * toUpperCase(char * string){
	int counter;
	if (string == NULL){
		#ifdef DEBUG
		printf("DEBUG::toUpperCase - Parameter string is NULL!\n");
		#endif
		return NULL;
	}
	char * uppercase = (char *)malloc(sizeof(char) * (strlen(string)+1));
	for(counter=0;counter<strlen(string); counter++)
		uppercase[counter]=toupper(string[counter]);
	uppercase[counter]='\0';
	
	return uppercase;

}

QBehavior * getQBehavior (char * qbehavior_name,QClass *qc)
{
	int i=0;
	
	if(qc == NULL)
	{
		#ifdef DEBUG
			printf("DEBUG::getQBehavior - Parameter qc is NULL!\n");
			return NULL;
		#endif
	}
	Node ** qbehaviors = getArray(qc->qbehaviors);
	for(i=0;i<qc->qbehaviors->length;i++) {
		QBehavior * qb = qbehaviors[i]->value;
		if(strcmp(qb->name,qbehavior_name) == 0)
			return qb;
	}
	
	
	return NULL;
}

QClass * getQClass (LinkedList * qclasses, char * qclass_name){
	int i,j;
	Node ** classes_array;
	
	if (qclasses == NULL || qclasses->length == 0){
		#ifdef DEBUG
		printf("DEBUG::getQClass - Parameter qclasses is NULL or empty!\n");
		#endif
		return NULL;
	}
	if (qclass_name == NULL || strlen(qclass_name) == 0){
		#ifdef DEBUG
		printf("DEBUG::getQClass - Parameter qclass_name is NULL or empty!\n");
		#endif
		return NULL;
	}
	classes_array = getArray(qclasses);
	
	
	for(i=0;i<qclasses->length;++i){
		QClass * qc = classes_array[i]->value;
		if(strcmp(qclass_name,qc->name)==0)
			return qc;
	}
	
	
	return NULL;
}

QState * getQState (LinkedList * qclasses, char * qstate_name){
	int i,j;
	Node ** classes_array;
	Node ** states_array;
	
	if (qclasses == NULL || qclasses->length == 0){
		#ifdef DEBUG
		printf("DEBUG::getQClass - Parameter qclasses is NULL or empty!\n");
		#endif
		return NULL;
	}
	if (qstate_name == NULL || strlen(qstate_name) == 0){
		#ifdef DEBUG
		printf("DEBUG::getQState - Parameter qstate_name is NULL or empty!\n");
		#endif
		return NULL;
	}
	classes_array = getArray(qclasses);
	
	#ifdef DEBUG
	printf("Looking for state named [%s]...\n",qstate_name);
	#endif
	
	for(i=0;i<qclasses->length;++i){
		QClass * qc = classes_array[i]->value;
		states_array = getArray(qc->qstates);
		
		for(j=0;j<qc->qstates->length;++j){
			QState * qs = states_array[j]->value;
			
			#ifdef DEBUG
			printf("\tWorking inside qstate [%s]\n",qs->name);
			printf("Inside class [%s]...\n",qs->qclass->name);
			printf("Comparation: [%s]==[%s]?\n\n",qstate_name,qs->name);
			#endif
			
			if(strcmp(qstate_name,qs->name)==0)
				return qs;
		}
	}	
	return NULL;
}

QBehavior * getQBehavior2 (LinkedList * qclasses, char * qbehavior_name){
	int i,j;
	Node ** classes_array;
	Node ** behaviors_array;
	
	if (qclasses == NULL || qclasses->length == 0){
		#ifdef DEBUG
		printf("DEBUG::getQBehavior2 - Parameter qclasses is NULL or empty!\n");
		#endif
		return NULL;
	}
	if (qbehavior_name == NULL || strlen(qbehavior_name) == 0){
		#ifdef DEBUG
		printf("DEBUG::getQBehavior2 - Parameter qbehavior_name is NULL or empty!\n");
		#endif
		return NULL;
	}
	classes_array = getArray(qclasses);
	
	#ifdef DEBUG
	printf("Looking for behavior named [%s]...\n",qbehavior_name);
	#endif
	
	for(i=0;i<qclasses->length;++i){
		QClass * qc = classes_array[i]->value;
		behaviors_array = getArray(qc->qbehaviors);
		
		for(j=0;j<qc->qbehaviors->length;++j){
			QBehavior * qb = behaviors_array[j]->value;
			
			#ifdef DEBUG
			printf("\tWorking inside qbehavior [%s]\n",qb->name);
			printf("Inside class [%s]...\n",qb->qclass->name);
			printf("Comparation: [%s]==[%s]?\n\n",qbehavior_name,qb->name);
			#endif
			
			if(strcmp(qbehavior_name,qb->name)==0)
				return qb;
		}
	}	
	return NULL;
}


void createBehaviors(LinkedList *qclasses, FILE * output){
	int i,j,count;
	Node ** classes_array;
	Node ** behaviors_array;
	
	if (qclasses == NULL || qclasses->length == 0){
		printf("No quantum behaviors were found.\n");
		return;
	}
	classes_array = getArray(qclasses);
	
	for(i=0;i<qclasses->length;++i){
		QClass * qc = classes_array[i]->value;
		#ifdef DEBUG
		printf("Working inside qclass [%s]\n",qc->name);
		#endif
		if (qc->qbehaviors == NULL || qc->qbehaviors->length == 0){
			printf("\tNo quantum behaviors were found within quantum class [%s].\n",qc->name);
			return ;
		}
		behaviors_array = getArray(qc->qbehaviors);
		
		for(j=0;j<qc->qbehaviors->length;++j){
			QBehavior * qb = behaviors_array[j]->value;
			#ifdef DEBUG
			printf("\tWorking inside qbehavior [%s]\n",qb->name);
			#endif
			
			fprintf(output,"class %sStrategy implements %sBehaviorStrategyImpl {\n",qb->name,qc->name);
			fprintf(output, "\tpublic void qBehavior(%sDataStructureImpl dsi){\n\t",qc->name);
			for(count=0;count < qb->code_length;count++)
				fprintf(output,"%c",qb->code[count]);
			fprintf(output, "\n\t}\n}");
		}
		
		//now lets print the enum-based abstract factory
		fprintf(output,"enum %sBehaviors{\n",qc->name);
		for(j=0;j<qc->qbehaviors->length;++j){
			QBehavior * qb = behaviors_array[j]->value;
			if(j > 0)
				fprintf(output,",\n");
			fprintf(output,"\t%s {\n\t\t%sBehaviorStrategyImpl factoryMethod(){\n\t\t\treturn new %sStrategy();\n\t\t}\n\t}",toUpperCase(qb->name),qc->name,qb->name); 
		}
		fprintf(output,";\n\tabstract %sBehaviorStrategyImpl factoryMethod();\n}\n",qc->name);
		
		fprintf(output,"\nclass %sBehaviorStrategy {\n",qc->name);
		fprintf(output,"\tprivate %sBehaviorStrategyImpl bsi;\n",qc->name);
		fprintf(output,"\tpublic %sBehaviorStrategy(%sBehaviors b){\n",qc->name,qc->name);
		fprintf(output,"\t\tbsi = b.factoryMethod();\n\t}\n");
		fprintf(output,"\tpublic void qBehavior(%sDataStructureImpl dsi){\n\t\tbsi.qBehavior(dsi);\n\t}\n}",qc->name);
		
		
	
	}
	
}

void createClasses(LinkedList *qclasses, FILE * output){
	int i,j,count;
	Node ** classes_array;
	Node ** behaviors_array;
	
	if (qclasses == NULL || qclasses->length == 0){
		printf("No quantum classes were found.\n");
		return;
	}
	classes_array = getArray(qclasses);
	
	for(i=0;i<qclasses->length;++i){
		QClass * qc = classes_array[i]->value;
		#ifdef DEBUG
		printf("Working inside qclass [%s]\n",qc->name);
		#endif
		if(qc->access_modifier.line > 0)
				fprintf(output,"%s ",qc->access_modifier.name);
		fprintf(output,"\nclass %s {\n",qc->name);
		//bkp fprintf(output,"\tprivate %sDataStructure d;\n",qc->name);
		fprintf(output,"\tprivate %sDataStructure _%sDataStructure;\n",qc->name,qc->name);
		fprintf(output,"\tpublic %s(%sDSTypes dst){\n",qc->name,qc->name);
		fprintf(output,"\t\t_%sDataStructure = new %sDataStructure(dst);\n\t}\n\t",qc->name,qc->name);
		fprintf(output,"public %s(){\n",qc->name);
		fprintf(output,"\t\t_%sDataStructure = new %sDataStructure(%sDSTypes.GROUNDSTATE);\n\t}\n",qc->name,qc->name,qc->name,qc->name);
		fprintf(output,"\tpublic %sDataStructure get%sDataStructure(){\n\treturn this._%sDataStructure;\n}\n",qc->name,qc->name,qc->name,qc->name);
		fprintf(output,"\tpublic void set%sDataStructure(%sDataStructure ds){\n\tthis._%sDataStructure = ds;\n}\n\t",qc->name,qc->name,qc->name,qc->name);
		for(count=0;count < qc->code_length;count++)
			fprintf(output,"%c",qc->code[count]);
		
		fprintf(output,"\n\tpublic void qBehavior(%sBehaviors b){\n",qc->name);
		fprintf(output,"\t\tnew %sBehaviorStrategy(b).qBehavior(_%sDataStructure.getDSImp());\n\t}\n}",qc->name,qc->name);
	}
}



void createStateCollapse(LinkedList *qclasses, char * var, char * state){
	



}

int soma(int a, int b){ return a+b; }
#endif
